package com.igoal.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.igoal.dao.CommentDAO;
import com.igoal.dao.GoalDAO;
import com.igoal.dao.NewsDAO;
import com.igoal.dao.UserActivityDAO;
import com.igoal.dao.UserDAOExt;
import com.igoal.dao.UserGoalEntryDAO;
import com.igoal.dao.UserGoalEntryDoneDAO;
import com.igoal.dao.UserStatusDAO;
import com.igoal.dao.UserThoughtDAO;
import com.igoal.dto.CommentDTO;
import com.igoal.dto.Commentable;
import com.igoal.entity.ActionTypeEnum;
import com.igoal.entity.Comment;
import com.igoal.entity.CommentCount;
import com.igoal.entity.ComponentEnum;
import com.igoal.entity.Entry;
import com.igoal.entity.ItemOwner;
import com.igoal.entity.News;
import com.igoal.entity.User;
import com.igoal.entity.UserGoalDone;
import com.igoal.entity.UserGoalEntry;
import com.igoal.entity.factory.EntityFactory;
import com.igoal.utils.EntityUtils;

@Service("commentService")
public class CommentServiceImpl extends BaseService<CommentDTO, Comment, Long>
		implements CommentService {

	private CommentDAO commentDAO;
	@Qualifier("userDAOExt")
	private UserDAOExt userDAO;
	private GoalDAO goalDAO;
	private UserGoalEntryDAO entryDAO;
	private UserGoalEntryDoneDAO entryDoneDAO;
	private UserStatusDAO userStatusDAO;
	private UserThoughtDAO userThoughtDAO;
	private UserActivityDAO userActivityDAO;
	private NewsDAO newsDAO;
	
	private ActionLoggerService actionLoggerService;

	@Autowired
	public void setActionLoggerService(ActionLoggerService actionLoggerService) {
		this.actionLoggerService = actionLoggerService;
	}

	@Autowired
	public void setNewsDAO(NewsDAO newsDAO) {
		this.newsDAO = newsDAO;
	}

	@Autowired
	public void setGoalDAO(GoalDAO goalDAO) {
		this.goalDAO = goalDAO;
	}

	@Autowired
	public void setEntryDAO(UserGoalEntryDAO entryDAO) {
		this.entryDAO = entryDAO;
	}

	@Autowired
	public void setEntryDoneDAO(UserGoalEntryDoneDAO entryDoneDAO) {
		this.entryDoneDAO = entryDoneDAO;
	}

	@Autowired
	public void setUserThoughtDAO(UserThoughtDAO userThoughtDAO) {
		this.userThoughtDAO = userThoughtDAO;
	}

	@Autowired
	public void setUserStatusDAO(UserStatusDAO userStatusDAO) {
		this.userStatusDAO = userStatusDAO;
	}

	@Autowired
	public void setUserDAO(UserDAOExt userDAO) {
		this.userDAO = userDAO;
	}

	@Autowired
	public void setCommentDAO(CommentDAO commentDAO) {
		this.commentDAO = commentDAO;
	}
	
	@Autowired
	public void setUserActivityDAO(UserActivityDAO userActivityDAO) {
		this.userActivityDAO = userActivityDAO;
	}

	public CommentDTO loadComment(Long id) {
		Comment comment = commentDAO.get(id);
		if (comment != null) {
			CommentDTO dto = new CommentDTO();
			dto.initFrom(comment);

			// do more here

			return dto;
		}

		return null;
	}

	public Long addComment(CommentDTO dto, String username) {
		if(dto != null){			
			try{
				User commentOwner = (User) userDAO.loadUserByUsername(username);
				Comment comment = EntityFactory.createComment(commentOwner);
				dto.setComment(com.igoal.utils.StringUtils.removeHTMLTags(dto.getComment()));
				dto.copyAttributesTo(comment);
				comment.setUser(commentOwner);
				
				comment = commentDAO.save(comment);
				
				ItemOwner item = loadItem(comment.getComponentId(), comment.getComponent());
				
				if(item != null){
					actionLoggerService.log(item.getOwner(), commentOwner, ActionTypeEnum.COMMENT, comment.getComponent(), comment.getComponentId());
					
					if(item instanceof CommentCount){
						CommentCount entry = (CommentCount) item;
						EntityUtils.increasePropertyValue(entry, "commentCount");
						if(item instanceof UserGoalEntry){
							entryDAO.save((UserGoalEntry)entry);
						}else if(item instanceof UserGoalDone){
							entryDoneDAO.save((UserGoalDone)entry);
						}
					}
				}
				
				return comment.getId();
			}catch (Exception e) {
				logger.error(e);				
			}
		}
		
		return new Long(SaveResult.FAIL);
	}
	
	private ItemOwner loadItem(Long componentId, ComponentEnum component) {
		ItemOwner item = null;

		// TODO: remove this stupid solution when has another :(
		switch (component) {
			case GOAL:
				item = goalDAO.get(componentId);
				break;
			case DONE_ENTRY:
				item = entryDoneDAO.get(componentId);
				break;
			case GOAL_ENTRY:
				item = entryDAO.get(componentId);
				break;
			case USER_STATUS:
				item = userStatusDAO.get(componentId);
				break;
			case USER_THOUGHT:
				item = userThoughtDAO.get(componentId);
				break;
			case USER_ACTIVITY:
				item = userActivityDAO.get(componentId);
				break;
			case NEWS:
				item = newsDAO.get(componentId);
				break;
		}

		return item;
	}

	public int deleteComment(Long commentId, String whoDelete) {
		try {
			Comment comment = commentDAO.get(commentId);
			if (comment == null) {
				return SaveResult.FAIL;
			}

			User requestDeleteUser = (User) userDAO.loadUserByUsername(whoDelete);

			User commentOwner = comment.getUser();
			
			boolean allowDelete = false;

			if (commentOwner == null) {
				// comment of guest
			} else if (commentOwner.equals(requestDeleteUser)) {
				// allow delete
				allowDelete = true;
			} else {
				// requestDeleteUser may be owner of comment component
				final ComponentEnum component = comment.getComponent();
				final Long componentId = comment.getComponentId();
				
				ItemOwner item = loadItem(componentId, component);
				if(item == null){
					//TODO: check why null and the action will do
				}else{
					User itemOwner = item.getOwner();
					
					if(requestDeleteUser.equals(itemOwner)){
						allowDelete = true;
					}
				}				
			}
			
			if(allowDelete){
				commentDAO.remove(comment.getId());
				
				ItemOwner item = loadItem(comment.getComponentId(), comment.getComponent());
				
				if(item != null && item instanceof Entry){
					Entry entry = (Entry) item;
					EntityUtils.descreasePropertyValue(entry, "commentCount");
					if(item instanceof UserGoalEntry){
						entryDAO.save((UserGoalEntry)entry);
					}else if(item instanceof UserGoalDone){
						entryDoneDAO.save((UserGoalDone)entry);
					}else if(item instanceof News){
						newsDAO.save((News)entry);
					}
				}
				
				return SaveResult.SUCCESS;
			}else{
				logger.error("User["+whoDelete+"] has not permission to delete the comment[id="+commentId+"]");
			}
		} catch (Exception e) {
			logger.error(e);
		}

		return SaveResult.FAIL;
	}

	public List<CommentDTO> loadAllCommentsBefore(Long componentId, ComponentEnum component, long updateBefore) {
		List<CommentDTO> result = new ArrayList<CommentDTO>();
		try {
			Date d = new Date(updateBefore);
			List<Comment> comments = commentDAO.getAllCommentsBefore(componentId, component, d);
			for (Comment comment : comments) {
				CommentDTO dto = new CommentDTO();
				dto.initFrom(comment);
				result.add(0, dto);
			}
		} catch (Exception e) {
			logger.error(e);
		}

		return result;
	}

	// public List<CommentDTO> loadComponentCommentsByPage(Long componentId,
	// ComponentEnum component, Date lastCommentOfPreviousPageDate,
	// boolean before) {
	// List<CommentDTO> result = new ArrayList<CommentDTO>();
	//
	// try{
	// List<Comment> comments = commentDAO.listCommentOfComponent(componentId,
	// component, lastCommentOfPreviousPageDate, before);
	//
	// for (Comment comment : comments) {
	// CommentDTO dto = new CommentDTO();
	// dto.initFrom(comment);
	//
	// // do more
	//
	// result.add(dto);
	// }
	//
	// }catch (Exception e) {
	// logger.error(e);
	// }
	//
	// return result;
	// }

	public void loadComments(Commentable item, ComponentEnum component) {
		if (item != null && component != null) {
			Long componentId = item.getId();
			List<CommentDTO> comments = getLatestComments(componentId, component);
			item.setComments(comments);
		}
	}

	public List<CommentDTO> getLatestComments(Long componentId, ComponentEnum component) {
		List<CommentDTO> result = new ArrayList<CommentDTO>();
		try {
			List<Comment> comments = commentDAO.getLatestComments(componentId, component);
			for (Comment comment : comments) {
				CommentDTO dto = new CommentDTO();
				dto.initFrom(comment);
				result.add(0, dto);
			}
		} catch (Exception e) {
			logger.error(e);
		}

		return result;
	}

}
